package com.csc.service;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.csc.bean.SystemAccountBean;
import com.csc.dao.LoginDAO;
import com.csc.dao.SystemAccountDAO;
import com.csc.domain.SystemAccount;

import constants.Constant;

@Service
public class ValidatorServiceImpl implements ValidatorService {

	/**
	 * ============== Password Regular Expression Pattern ==============
	 */
	@Autowired
	LoginDAO loginDao;

	@Autowired
	private SystemAccountService sysAccSer;

	@Autowired
	SystemRequestService requestService;

	@Autowired
	SystemAccountDAO sysAccDao;

	private static final Logger logger = Logger
			.getLogger(ValidatorServiceImpl.class);

	public String encodePassword(String rawPass) throws DataAccessException {
		logger.info("Encoding password.");
		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		return passwordEncoder.encode(rawPass);
	}

	public boolean isPasswordValid(String encPass, String rawPass, Object salt)
			throws DataAccessException {
		logger.info("Validating password.");
		return BCrypt.checkpw(rawPass, encPass);
	}

	public String checkUpdatePassword(String userName, String oldPass,
			String newPass, String confPass) {
		boolean check = true;
		String message = "";

		/*
		 * if (oldPass.equals("")) { message +=
		 * "<br>Old password cannot left blank</br>"; check = false; }
		 * 
		 * if (newPass.equals("")) { message +=
		 * "<br>New password cannot left blank</br>"; check = false; }
		 * 
		 * if (confPass.equals("")) { message +=
		 * "<br>Confirm new password cannot left blank</br>"; check = false; }
		 */

		SystemAccount sysAcc = sysAccDao.getAccountByLoginId(userName);
		// BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		if (!BCrypt.checkpw(oldPass, sysAcc.getAccountPassword())) {
			message += "<br>Old password is not correct</br>";
			check = false;
		} else {
			if (!confPass.equals(newPass)) {
				message += "<br>Confirm new password is not the same to new password</br>";
				check = false;
			}

			Pattern pattern = Pattern.compile(Constant.PASSWORD_PATTERN);
			Matcher matcher1 = pattern.matcher(newPass);
			Matcher matcher2 = pattern.matcher(confPass);
			if (!matcher1.matches() || !matcher2.matches()) {
				message += "<br>New password is not valid</br>";
				check = false;
			}
		}
		if (check)
			return null;
		else
			return message;
	}

	public String checkFullName(String fName, String lName, String mName) {

		String message = "";
		if (fName.equals("")) {
			message += "First Name can not left blank!!!<br>";
		}
		if (fName.length() > 15 || fName.length() < 1) {
			message += "First Name must have 1 - 15 letters.<br>";
		}
		if (lName.equals("")) {
			message += "Last Name Name can not left blank!!!<br>";
		}
		if (lName.length() > 20 || lName.length() < 1) {
			message += "Last Name must have 1 - 20 letters.";
		}
		if (mName.length() > 20) {
			message += "Mid Name must have 0 - 20 letters.";
		}
		return message;
	}

	public String checkIDCardNumber(String idCardNumber) {
		String message = "";
		String checkNo = "^\\+?[0-9]$";
		Pattern pattern = Pattern.compile(checkNo);

		if (idCardNumber.equals("")) {
			message += "ID Card Number can not left blank!!!<br>";
		}
		if (!pattern.matcher(idCardNumber).matches()) {
			message += "Invalid Id Card Number";
		}
		if (idCardNumber.length() > 12 || idCardNumber.length() < 9) {
			message += "ID Card Number must have 9 - 12 number.";
		}
		return message;
	}

	public String checkPhoneNumber(String phone1, String phone2) {

		String checkPhoneNo = "^\\+?[0-9]$";
		Pattern pattern = Pattern.compile(checkPhoneNo);
		String message = "";

		if (phone1.equals("")) {
			message += "Phone 1 Number can not left blank!!!<br>";
		}
		if (!pattern.matcher(phone1).matches()) {
			message += "Invalid Phone 1";
		}
		if (phone1.length() > 12 || phone1.length() < 9) {
			message += "Phone 1 must have 9 - 12 number.";
		}
		if (phone2.length() > 0) {
			if (!pattern.matcher(phone2).matches()) {
				message += "Invalid Phone 2 Number";
			}
			if (phone2.length() > 12 || phone2.length() < 9) {
				message += "Phone 2 must have 9 - 12 number.";
			}
		}
		return message;
	}

	public String checkAddress(String address1, String address2) {
		String message = "";
		if (address1.equals("")) {
			message += "Address 1 can not left blank!!!<br>";
		}
		if (address1.length() > 150 || address1.length() < 1) {
			message += "Address 1 must have 1 - 150 letters.<br>";
		}
		if (address2.length() > 0) {
			if (address2.length() > 150 || address2.length() < 0) {
				message += "Address 2 must have 0 - 150 letters.<br>";
			}
		}
		return message;
	}

	public String checkEmail(String email1, String email2) {
		String message = "";
		String checkEmail = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
		Pattern pattern = Pattern.compile(checkEmail);

		if (email1.equals("")) {
			message += "Email 1 can not left blank!!!<br>";
		}
		if (email1.length() > 150 || email1.length() < 1) {
			message += "Email 1 must have 1 - 150 letters.<br>";
		}
		if (!pattern.matcher(email1).matches()) {
			message += "Invalid email 1. <br>";
		}
		if (email2.length() > 0) {
			if (email2.length() > 50 || email2.length() < 0) {
				message += "Email 2 must have 0 - 50 letters.<br>";
			}
			if (!pattern.matcher(email2).matches()) {
				message += "Invalid email 2. <br>";
			}
		}
		return message;
	}

	@Override
	public String[] checkAccountProperties(SystemAccountBean acc) {
		// TODO Auto-generated method stub
		String message = "";
		List<SystemAccount> list = sysAccDao.getRegisteredAccounts("admin");

		// Validate Username
		String username = acc.getAccountLoginId();

		if (username.equals("")) {
			message += "- What's your username? <br>";
		} else if (sysAccDao.getAccountByUsername(username) == null) {
			message += "- " + Constant.ACCOUNT_NOT_EXISTING + "! <br>";
		}
		// Validate Username

		// Validate ID Card Number
		String IDCard = acc.getAccountIDCardNumber();
		long id = 0;
		try {
			id = Long.parseLong(IDCard);
		} catch (NumberFormatException nfe) {
			// TODO: handle exception
			id = 0;
		}

		if (IDCard.equals("")) {
			message += "- What's your ID Card Number? <br>";
		} else if (id == 0) {
			message += "- Invalid ID Card Number! ID Card must consist of an 9 - 12 digit code <br>";
		} else if (IDCard.length() > 12 || IDCard.length() < 9) {
			message += "- Invalid ID Card Number! ID Card must consist of an 9 - 12 digit code <br>";
		} else {

			for (SystemAccount systemAccount : list) {
				if (systemAccount.getAccountLoginId().equals(
						acc.getAccountLoginId())) {
					continue;
				}
				if (systemAccount.getAccountIDCardNumber().equals(IDCard)) {
					message += "- "
							+ IDCard
							+ " is already in use. Please enter another ID! <br>";
					break;
				}
			}
		}
		// End - Validate ID Card Number

		// Validate First Name
		String firstName = acc.getAccountFirstName();
		if (firstName.equals("")) {
			message += "- What's your first name? <br>";
		} else if (firstName.length() > 20) {
			message += "- Your first name is too long, please use your real name! <br>";
		}
		// End - Validate First Name

		// Validate Mid Name
		String midName = acc.getAccountMidName();
		if (midName.length() > 20) {
			message += "- Your mid name is too long, please use your real name! <br>";
		}
		// End - Validate Mid Name

		// Validate Last Name
		String lastName = acc.getAccountLastName();
		if (lastName.equals("")) {
			message += "- What's your last name? <br>";
		} else if (lastName.length() > 20) {
			message += "- Your last name is too long, please use your real name! <br>";
		}
		// End - Validate last Name

		// Validate Phone
		String phone1 = acc.getAccountPhone1();
		String phone2 = acc.getAccountPhone2();
		long p1 = 0;
		long p2 = 0;

		try {
			p1 = Long.parseLong(phone1);
		} catch (NumberFormatException e) {
			// TODO: handle exception
			p1 = 0;
		}

		try {
			p2 = Long.parseLong(phone2);
		} catch (NumberFormatException e) {
			// TODO: handle exception
			p2 = 0;
		}

		if (phone1.equals(phone2)) {
			message += "- You cannot use the same phone number for phone 1 and phone 2! <br>";
		} else {

			// Phone 1
			if (phone1.equals("")) {
				message += "- Please input your phone number? <br>";
			} else if (p1 == 0) {
				message += "- Invalid Phone 1, Phone number may have from 9 to 12 digits! <br>";
			} else if (phone1.length() > 12 || phone1.length() < 9) {
				message += "- Invalid Phone 1, Phone number may have from 9 to 12 digits! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountPhone1().equals(phone1)
							|| systemAccount.getAccountPhone2().equals(phone1)) {
						message += "- "
								+ phone1
								+ " is already in use. Please enter another Phone Number! <br>";
						break;
					}
				}
			}
			// End - Phone 1
			// Phone 2
			if (p2 == 0) {
				message += "- Invalid Phone 2, Phone number may have from 9 to 12 digits! <br>";
			} else if (phone2.length() > 12 || phone2.length() < 9) {
				message += "- Invalid Phone 2, Phone number may have from 9 to 12 digits! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountPhone2().equals(phone2)
							|| systemAccount.getAccountPhone2().equals(phone2)) {
						message += "- "
								+ phone2
								+ " is already in use. Please enter another Phone Number! <br>";
						break;
					}
				}
			}
			// End - Phone 2
		}
		// End - Validate Phone

		// Validate Email
		String email1 = acc.getAccountEmail1();
		String email2 = acc.getAccountEmail2();
		String checkEmail = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
		Pattern patternEmail = Pattern.compile(checkEmail);

		if (email1.equals(email2)) {
			message += "- You cannot use the same email for email 1 and email 2! <br>";
		} else {
			// Email 1
			if (email1.equals("")) {
				message += "- Please input Email 1, Email wil be used to login and communicate with your colleagues! <br>";
			} else if (!patternEmail.matcher(email1).matches()) {
				message += "- Invalid Email 1! An email is made up of a local part, an @ symbol, then a domain part! Ex: james@csc.com! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountEmail1().equals(email1)
							|| systemAccount.getAccountEmail2().equals(email1)) {
						message += "- "
								+ email1
								+ " is already in use. Please enter another Email! <br>";
						break;
					}
				}
			}
			// End - Email 1
			// Email 2
			if (!patternEmail.matcher(email2).matches()) {
				message += "- Invalid Email 2! An email is made up of a local part, an @ symbol, then a domain part! Ex: james@csc.com! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountEmail1().equals(email2)
							|| systemAccount.getAccountEmail2().equals(email2)) {
						message += "- "
								+ email2
								+ " is already in use. Please enter another Email! <br>";
						break;
					}
				}
			}
			// End - Email 2
		}
		// End - Validate Email

		// Validate Address
		String address1 = acc.getAccountAddress1();

		if (address1.equals("")) {
			message += "- Please input Address 1, We will contact you via your address in case of emergency! <br>";
		}
		// End - Validate Address

		// Confirm Valid
		if (message.equals("")) {
			message = "valid";
		}

		// End Confirm Valid
		String[] array = { message };
		return array;
	}

	@Override
	public String checkRequestResetPassword(String username) {
		// TODO Auto-generated method stub

		String message = "";
		boolean exist = sysAccSer.getAccountByUsername(username) != null;
		String status;

		try {
			status = sysAccSer.getAccountByUsername(username).getSystemStatus()
					.getStatusName();
		} catch (Exception e) {
			// TODO: handle exception
			status = "New";
		}

		if (!exist || !status.equals("Active")) {
			message = Constant.ACCOUNT_NOT_EXISTING;
		} else {
			boolean isAvailable = requestService
					.isAccountStatusRequestAvailable(username);
			if (!isAvailable) {
				message = "You've already requested to reset password. <br>"
						+ "Please check your email account for new password.";
			}
		}
		
		return message;
	}

	@Override
	public String[] checkCreateAccount(SystemAccountBean acc) {
		// TODO Auto-generated method stub
		String message = "";
		List<SystemAccount> list = sysAccDao.getRegisteredAccounts("");

		//validate role
		String role = acc.getRole();
		if(role.equals("")){
			message += "- What's your role? <br>";
		}
		// Validate Username
		String username = acc.getAccountLoginId();

		if (username.equals("")) {
			message += "- What's your username? <br>";
		} else if (sysAccDao.getAccountByUsername(username) != null) {
			message += "- " + Constant.ACCOUNT_EXISTING + "! <br>";
		}
		// Validate Username

		// Validate ID Card Number
		String IDCard = acc.getAccountIDCardNumber();
		long id = 0;
		try {
			id = Long.parseLong(IDCard);
		} catch (NumberFormatException nfe) {
			// TODO: handle exception
			id = 0;
		}

		if (IDCard.equals("")) {
			message += "- What's your ID Card Number? <br>";
		} else if (id == 0) {
			message += "- Invalid ID Card Number! ID Card must consist of an 9 - 12 digit code <br>";
		} else if (IDCard.length() > 12 || IDCard.length() < 9) {
			message += "- Invalid ID Card Number! ID Card must consist of an 9 - 12 digit code <br>";
		} else {

			for (SystemAccount systemAccount : list) {
				if (systemAccount.getAccountLoginId().equals(
						acc.getAccountLoginId())) {
					continue;
				}
				if (systemAccount.getAccountIDCardNumber().equals(IDCard)) {
					message += "- "
							+ IDCard
							+ " is already in use. Please enter another ID! <br>";
					break;
				}
			}
		}
		// End - Validate ID Card Number

		// Validate First Name
		String firstName = acc.getAccountFirstName();
		if (firstName.equals("")) {
			message += "- What's your first name? <br>";
		} else if (firstName.length() > 20) {
			message += "- Your first name is too long, please use your real name! <br>";
		}
		// End - Validate First Name

		// Validate Mid Name
		String midName = acc.getAccountMidName();
		if (midName.length() > 20) {
			message += "- Your mid name is too long, please use your real name! <br>";
		}
		// End - Validate Mid Name

		// Validate Last Name
		String lastName = acc.getAccountLastName();
		if (lastName.equals("")) {
			message += "- What's your last name? <br>";
		} else if (lastName.length() > 20) {
			message += "- Your last name is too long, please use your real name! <br>";
		}
		// End - Validate last Name

		// Validate Phone
		String phone1 = acc.getAccountPhone1();
		String phone2 = acc.getAccountPhone2();
		long p1 = 0;
		long p2 = 0;

		try {
			p1 = Long.parseLong(phone1);
		} catch (NumberFormatException e) {
			// TODO: handle exception
			p1 = 0;
		}

		try {
			p2 = Long.parseLong(phone2);
		} catch (NumberFormatException e) {
			// TODO: handle exception
			p2 = 0;
		}

		if (phone1.equals(phone2)) {
			message += "- You cannot use the same phone number for phone 1 and phone 2! <br>";
		} else {

			// Phone 1
			if (phone1.equals("")) {
				message += "- Please input your phone number? <br>";
			} else if (p1 == 0) {
				message += "- Invalid Phone 1, Phone number may have from 9 to 12 digits! <br>";
			} else if (phone1.length() > 12 || phone1.length() < 9) {
				message += "- Invalid Phone 1, Phone number may have from 9 to 12 digits! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountPhone1().equals(phone1)
							|| systemAccount.getAccountPhone2().equals(phone1)) {
						message += "- "
								+ phone1
								+ " is already in use. Please enter another Phone Number! <br>";
						break;
					}
				}
			}
			// End - Phone 1
			// Phone 2
			if (p2 == 0) {
				message += "- Invalid Phone 2, Phone number may have from 9 to 12 digits! <br>";
			} else if (phone2.length() > 12 || phone2.length() < 9) {
				message += "- Invalid Phone 2, Phone number may have from 9 to 12 digits! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountPhone2().equals(phone2)
							|| systemAccount.getAccountPhone2().equals(phone2)) {
						message += "- "
								+ phone2
								+ " is already in use. Please enter another Phone Number! <br>";
						break;
					}
				}
			}
			// End - Phone 2
		}
		// End - Validate Phone

		// Validate Email
		String email1 = acc.getAccountEmail1();
		String email2 = acc.getAccountEmail2();
		String checkEmail = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
		Pattern patternEmail = Pattern.compile(checkEmail);

		if (email1.equals(email2)) {
			message += "- You cannot use the same email for email 1 and email 2! <br>";
		} else {
			// Email 1
			if (email1.equals("")) {
				message += "- Please input Email 1, Email wil be used to login and communicate with your colleagues! <br>";
			} else if (!patternEmail.matcher(email1).matches()) {
				message += "- Invalid Email 1! An email is made up of a local part, an @ symbol, then a domain part! Ex: james@csc.com! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountEmail1().equals(email1)
							|| systemAccount.getAccountEmail2().equals(email1)) {
						message += "- "
								+ email1
								+ " is already in use. Please enter another Email! <br>";
						break;
					}
				}
			}
			// End - Email 1
			// Email 2
			if (!patternEmail.matcher(email2).matches()) {
				message += "- Invalid Email 2! An email is made up of a local part, an @ symbol, then a domain part! Ex: james@csc.com! <br>";
			} else {
				for (SystemAccount systemAccount : list) {
					if (systemAccount.getAccountLoginId().equals(
							acc.getAccountLoginId())) {
						continue;
					}
					if (systemAccount.getAccountEmail1().equals(email2)
							|| systemAccount.getAccountEmail2().equals(email2)) {
						message += "- "
								+ email2
								+ " is already in use. Please enter another Email! <br>";
						break;
					}
				}
			}
			// End - Email 2
		}
		// End - Validate Email

		// Validate Address
		String address1 = acc.getAccountAddress1();

		if (address1.equals("")) {
			message += "- Please input Address 1, We will contact you via your address in case of emergency! <br>";
		}
		// End - Validate Address

		// Confirm Valid

		// End Confirm Valid
		String[] array = { message };
		return array;
	}
}
